package com.miaosmart.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.miaosmart.common.context.UserContext;
import com.miaosmart.common.convention.exception.ClientException;
import com.miaosmart.dto.req.EmailVerficationReqDTO;
import com.miaosmart.dto.req.LoginReqDTO;
import com.miaosmart.dto.req.RegisterReqDTO;
import com.miaosmart.dto.req.UserUpdateReqDTO;
import com.miaosmart.dto.resp.GetUserInfoRespDTO;
import com.miaosmart.dto.resp.LoginRespDTO;
import com.miaosmart.dto.resp.RegisterRespDTO;
import com.miaosmart.dto.resp.UserUpdateRespDTO;
import com.miaosmart.entity.User;
import com.miaosmart.mapper.UserMapper;
import com.miaosmart.service.AuthService;
import com.miaosmart.service.MailService;
import com.miaosmart.util.AliOssUtil;
import com.miaosmart.util.JwtUtil;
import com.miaosmart.util.PasswordEncoder;
import com.miaosmart.util.RedisUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {

    private final UserMapper userMapper;
    private final RedisUtil redisUtil;
    private final JwtUtil jwtUtil;
    private final MailService mailService;
    private final AliOssUtil aliOssUtil;


    @Override
    public void sendVerificationCode(EmailVerficationReqDTO email) {
        String emailString = email.getEmail();
        if (emailString == null || emailString.isEmpty()) {
            throw new ClientException("邮箱不能为空");
        }



        // 检查冷却时间
        String cooldownKey = "verification:cooldown:" + emailString;
        if (Boolean.TRUE.equals(redisUtil.hasKey(cooldownKey))) {
            throw new ClientException("发送验证码频繁");
        }

        // 生成6位数字验证码
        String code = RandomUtil.randomNumbers(6);
        
        // 存储验证码，5分钟有效期
        String codeKey = "verification:code:" + emailString;
        redisUtil.set(codeKey, code, 5, TimeUnit.MINUTES);
        
        // 设置冷却时间
        redisUtil.set(cooldownKey, "", 60, TimeUnit.SECONDS);

        // 发送邮件
        try {
            mailService.sendVerificationCode(emailString, code);
        } catch ( Exception e) {
            throw  new ClientException("邮件发送失败");
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RegisterRespDTO register(RegisterReqDTO registerDTO) {
        // 验证验证码
        String codeKey = "verification:code:" + registerDTO.getEmail();
        String code = redisUtil.get(codeKey);
        if (code == null || !code.equals(registerDTO.getVerificationCode())) {
            throw new ClientException("验证码错误或已过期");
        }

        // 检查用户名和邮箱是否已存在
        if (checkUserExists(registerDTO.getUsername(), registerDTO.getEmail())) {
            throw new ClientException("用户名或邮箱已存在");
        }

        // 插入用户数据
        User user = new User();
        BeanUtils.copyProperties( registerDTO, user);
        user.setPassword(PasswordEncoder.encode(registerDTO.getPassword()));
        user.setNickname(registerDTO.getUsername());
        int rows = userMapper.insert(user); // 插入数据
        if (rows <= 0) {
            throw new ClientException("用户表插入失败");
        }
        
        // 删除验证码
        redisUtil.delete(codeKey);
        
        return new RegisterRespDTO()
                .setUserId(user.getUserId())
                .setEmail(user.getEmail())
                .setRole( user.getRole())
                .setUsername(user.getUsername());

    }

    @Override
    public LoginRespDTO login(LoginReqDTO loginDTO) {
        // 查找用户
        User user = userMapper.selectOne(
            new LambdaQueryWrapper<User>()
                .eq(User::getUsername, loginDTO.getAccount())
                .or()
                .eq(User::getEmail, loginDTO.getAccount())
        );

        if ( user == null) {
            throw new ClientException("该用户不存在");
        }
        // 加密密码
//        String encodedPassword = PasswordEncoder.encode(loginDTO.getPassword());
        if (!PasswordEncoder.matches(loginDTO.getPassword(), user.getPassword())) {
            throw new ClientException("账号或密码错误");
        }

        // 更新最后登录时间
        user.setLastLoginAt(LocalDateTime.now());
        userMapper.updateById(user);

        // 生成token
        String token = jwtUtil.generateToken(user);

        LoginRespDTO loginRespDTO = new LoginRespDTO();
        loginRespDTO.setUsername(user.getUsername());
        loginRespDTO.setNickname(user.getNickname());
        loginRespDTO.setRole(user.getRole());
        loginRespDTO.setToken(token);
        loginRespDTO.setAvatar(user.getAvatar());
        loginRespDTO.setEmail(user.getEmail());

        return loginRespDTO;
    }

    @Override
    public GetUserInfoRespDTO getCurrentUser() {
        // TODO: 从SecurityContext获取当前用户
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserUpdateRespDTO updateUser(UserUpdateReqDTO userUpdateDTO) throws IOException {
        String userId = UserContext.getUserId();

        // 获取用户信息
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new ClientException("用户不存在");
        }

        // 如果要修改密码，先验证旧密码
        if (userUpdateDTO.getOldPassword() != null && userUpdateDTO.getNewPassword() != null) {
            if (!PasswordEncoder.matches(userUpdateDTO.getOldPassword(), user.getPassword())) {
                throw new ClientException("原密码错误");
            }
            user.setPassword(PasswordEncoder.encode(userUpdateDTO.getNewPassword()));
        }

        // 更新用户信息
        user.setNickname(userUpdateDTO.getNickname());
        if (userUpdateDTO.getAvatar() != null && !userUpdateDTO.getAvatar().isEmpty()) {

            MultipartFile file = userUpdateDTO.getAvatar();
            //原始文件名
            String originalFilename = file.getOriginalFilename();
            //截取原始文件名的后缀   dfdfdf.png
            String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
            //构造新文件名称：防止上传到阿里云的文件，因为名字重复导致覆盖的问题
            String objectName = UUID.randomUUID().toString() + extension;


            String filePath = aliOssUtil.upload(file.getBytes(), objectName);
            user.setAvatar(filePath);
        }

        user.setUpdatedAt(LocalDateTime.now());

        // 更新到数据库
        int rows = userMapper.updateById(user);
        if (rows <= 0) {
            throw new ClientException("更新用户信息失败");
        }

        // 返回更新后的信息
        return new UserUpdateRespDTO()
                .setNickname(user.getNickname())
                .setAvatar(user.getAvatar());


    }

    private boolean checkUserExists(String username, String email) {
        return userMapper.exists(
            new LambdaQueryWrapper<User>()
                .eq(User::getUsername, username)
                .or()
                .eq(User::getEmail, email)
        );
    }
} 